package bb.lanxing.activity.bluetooth

import android.annotation.SuppressLint
import android.app.ProgressDialog
import android.content.BroadcastReceiver
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.os.CountDownTimer
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.View
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.RadioGroup
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import bb.lanxing.R
import bb.lanxing.activity.base.BaseDisplayActivity
import bb.lanxing.calc.data.DisplayPoint
import bb.lanxing.databinding.ActivityCadence01StatusBinding
import bb.lanxing.devices.utils.XZDeviceHelper
import bb.lanxing.lib.devices.api.ConnectionListener
import bb.lanxing.lib.devices.api.DeviceManager
import bb.lanxing.lib.devices.api.SmartDevice
import bb.lanxing.lib.devices.base.DeviceContext
import bb.lanxing.lib.devices.ble.BleCons
import bb.lanxing.lib.devices.ble.dfu.DfuContext
import bb.lanxing.lib.devices.ble.dfu.IDfuProgressCallback
import bb.lanxing.lib.devices.core.utils.DeviceHelper
import bb.lanxing.lib.devices.utils.CadenceUtils
import bb.lanxing.lib.devices.utils.DeviceVersionHelper
import bb.lanxing.manager.RemoteSharedPreference
import bb.lanxing.manager.SPConstant
import bb.lanxing.model.database.Device
import bb.lanxing.network.BiCiCallback
import bb.lanxing.network.MyHttpClient
import bb.lanxing.util.FileDownloadUtils
import bb.lanxing.util.ui.BadgeView
import bb.lanxing.view.BiciAlertDialogBuilder
import com.github.mikephil.charting.utils.Utils
import gov.nist.core.Separators
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.json.JSONObject
import java.io.File
import java.text.DecimalFormat
import java.util.Objects

class Cadence01StatusActivity : BaseDisplayActivity(), ConnectionListener, IDfuProgressCallback {
    private lateinit var batteryView: TextView
    private lateinit var cadenceView: TextView
    private lateinit var llCadence: LinearLayout
    private lateinit var llSpeed: LinearLayout
    private lateinit var radioCadence: RadioButton
    private lateinit var radioGroupType: RadioGroup
    private lateinit var radioSpeed: RadioButton
    private lateinit var speedView: TextView

    private lateinit var tvManufacture: TextView
    private lateinit var mIbUpgradeFirmware: ImageButton
    private lateinit var tvModel: TextView
    private lateinit var tvVersion: TextView
    private lateinit var unbindBtn: TextView
    private lateinit var wheelLengthView: TextView
    private lateinit var wheelSettingView: RelativeLayout

    private var device: Device? = null
    private var switchModeTimer: CountDownTimer? = null
    private val decimalFormat = DecimalFormat("0.00")
    private val handler = Handler(Looper.getMainLooper())
    private var mDfuContext: DfuContext? = null
    private var mDfuProgressDialog: ProgressDialog? = null
    private var lastTime: Long = 0
    private var lastSpeedTime: Long = 0
    private var isSwitchMode = false
    private var isShowFailToast = true
    private var dfuFilePath: String = ""
    private var downloadUrl: String? = ""
    private var verName: String? = ""
    private var isChecking = false

    private lateinit var binding: ActivityCadence01StatusBinding

    private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            Log.d(TAG, "$javaClass onReceive action = $action")
            when (Objects.requireNonNull(action)) {
                BleCons.ACTION_DEVICE_INFORMATION -> {
                    if (intent.getIntExtra("EXTRA_DEVICE_TYPE", 0) != SmartDevice.TYPE_CADENCE01) {
                        return
                    }
                    val stringExtra = intent.getStringExtra("EXTRA_DEVICE_INFORMATION")
                    if (stringExtra != null) {
                        setUIVersion(stringExtra)
                    }
                    val stringExtra2 = intent.getStringExtra("EXTRA_MODEL")
                    if (stringExtra2 != null) {
                        setUIModel(stringExtra2)
                        if (device != null) {
                            DeviceVersionHelper.setModelVersion(
                                context, device!!.address, stringExtra2
                            )
                        }
                    }
                    val stringExtra3 = intent.getStringExtra("EXTRA_EXTRA_MANUFACTURE")
                    if (stringExtra3 != null) {
                        setUIManufacture(stringExtra3)
                    }
                    val cscFeature = intent.getIntExtra("EXTRA_CSC_FUTURE", -1)
                    Log.d(
                        TAG, "onReceive cscFeature=$cscFeature"
                    )
                    if (cscFeature != -1) {
                        setMode();
                    }
                }

                BleCons.ACTION_READ_DEVICE_INFORMATION_RESULT -> {
                    val stringExtra4 = intent.getStringExtra(BleCons.EXTRA_MANUFACTURE)
                    val stringExtra5 = intent.getStringExtra(BleCons.EXTRA_FIRMWARE_VERSION)
                    val stringExtra6 = intent.getStringExtra(BleCons.EXTRA_MODEL)
                    val intExtra = intent.getIntExtra(BleCons.EXTRA_BATTERY, 0)
                    if (stringExtra4 == null || stringExtra5 == null || stringExtra6 == null || stringExtra4.isEmpty() || stringExtra5.isEmpty() || stringExtra6.isEmpty()) {
                        requestDeviceInfo()
                    }
                    if (intExtra == 0) {
                        requestBattery()
                    } else {
                        setUIBattery(intExtra)
                    }
                    if (stringExtra4 != null) {
                        setUIManufacture(stringExtra4)
                    }
                    if (stringExtra5 != null) {
                        setUIVersion(stringExtra5)
                        DeviceContext.saveDeviceVersion(device!!.address, stringExtra5)
                    }
                    if (stringExtra6 != null) {
                        setUIModel(stringExtra6)
                    }
                }

                BleCons.ACTION_BATTERY -> {
                    if (intent.getIntExtra(
                            BleCons.EXTRA_DEVICE_TYPE, 0
                        ) == SmartDevice.TYPE_CADENCE01
                    ) {
                        setUIBattery(intent.getIntExtra(BleCons.EXTRA_BATTERY, 0))
                    }
                }

                else -> {}
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(bundle: Bundle?) {
        super.onCreate(bundle)
        binding = ActivityCadence01StatusBinding.inflate(layoutInflater)
        setContentView(binding.root)
        bindView()
        setupActionBar(true)
        //        XZDeviceHelper.registerConnectionStateListener(this);
        DeviceHelper.registerConnectionStateListener(this)
        registerReceiver()
        val byAddress = Device.getByAddress(
            intent.getStringExtra(BleCons.EXTRA_DEVICE_ADDRESS)
        )
        device = byAddress
        if (byAddress == null) {
            finish()
            return
        }
        wheelSettingView.setOnClickListener { showWheelSettingDialog() }

        unbindBtn.setOnClickListener { unBoundDeviceConfirm() }
        if (!device?.deviceFwDisplayVersion.isNullOrEmpty()) {
            checkVersion(device?.deviceFwDisplayVersion)
        }
    }

    @SuppressLint("SetTextI18n")
    override fun onResume() {
        super.onResume()
        handler.postDelayed({
            val f =
                RemoteSharedPreference.getInstance().getFloat(SPConstant.KEY_WHEEL_LENGTH, 2.171f)
            val textView = wheelLengthView
            textView.text = ((f * 1000.0f).toInt()).toString() + " mm"
            if (BadgeView.shouldShowByFirstTime(wheelLengthView)) {
                BadgeView(activity).setAutoHide(true).setBadgeMargin(0, 0, 15, 0)
                    .setHideOnNull(false).setOnHideListener {
                        BadgeView.setNotFirst(
                            wheelLengthView
                        )
                    }.toTargetView(wheelLengthView)
            }
        }, 200L)
        if (device != null) {
            if (XZDeviceHelper.isConnected(SmartDevice.TYPE_CADENCE01) || XZDeviceHelper.isConnecting(
                    device!!.address
                )
            ) {
                setMode()
                requestBattery()
                readDeviceInfo()
            } else {
                XZDeviceHelper.connect(device)
            }
        }
    }

    fun unBoundDeviceConfirm() {
        BiciAlertDialogBuilder(this).setTitle(R.string.st_forget_sensor)
            .setMessage(R.string.st_are_you_sure_unbind).setPositiveButton(
                R.string.mine_profile_dialog_btn_unbind
            ) { _: DialogInterface?, i: Int ->
                if (device!!.deviceNumber > 0) {
                    MyHttpClient.deleteDevice(device!!.deviceNumber)
                }
                isShowFailToast = false
                DeviceContext.getDeviceProvider().removeByTypeAndFlag(device!!.type, device!!.flags)
                DeviceContext.getDeviceManager().disconnect(device!!.address)
                DeviceContext.startAndRefreshAutoConnector()
                finish()
            }.setNegativeButton(
                R.string.str_sync_cancel
            ) { _: DialogInterface?, i: Int -> }.show().setCanceledOnTouchOutside(true)
    }

    fun setMode() {
        device = Device.getByAddress(device!!.address)
        radioGroupType.setOnCheckedChangeListener(null)
        device?.let {
            if (it.type == SmartDevice.TYPE_CADENCE01) {
                Log.d(TAG, "setMode address=" + it.address)
                Log.d(TAG, "setMode flags=" + it.flags)
                if (CadenceUtils.hasWheelRevolution(it.flags)) {
                    llSpeed.visibility = View.VISIBLE
                    llCadence.visibility = View.GONE
                    radioSpeed.isChecked = true
                    wheelSettingView.visibility = View.VISIBLE
                } else if (CadenceUtils.hasCrankRevolution(it.flags)) {
                    llCadence.visibility = View.VISIBLE
                    llSpeed.visibility = View.GONE
                    radioCadence.isChecked = true
                    wheelSettingView.visibility = View.GONE
                }
            }
            radioGroupType.setOnCheckedChangeListener(SwitchCadenceOrSpeed())
        }

    }


    inner class SwitchCadenceOrSpeed internal constructor() : RadioGroup.OnCheckedChangeListener {
        override fun onCheckedChanged(group: RadioGroup, checkedId: Int) {

            if (radioSpeed.isChecked) {
                if (XZDeviceHelper.getCadence01Controller() != null) {
                    isSwitchMode = XZDeviceHelper.getCadence01Controller().switchTo(1)
                }
            } else {
                if (XZDeviceHelper.getCadence01Controller() != null) {
                    isSwitchMode = XZDeviceHelper.getCadence01Controller().switchTo(0)
                }
            }
            showLoadingDialog(
                "切换模式中，切换完成后需再次手动连接" as CharSequence, false
            )

            this@Cadence01StatusActivity.switchModeTimer = object : CountDownTimer(3000L, 3000L) {
                override fun onTick(millisUntilFinished: Long) {
                }

                override fun onFinish() {
                    if (isSwitchMode) {
                        this@Cadence01StatusActivity.dismissLoadingDialog()
                        this@Cadence01StatusActivity.toast("切换成功，请重新连接设备")
                        device!!.delete()
                        XZDeviceHelper.disconnect(device?.address)
                        radioGroupType.postDelayed(
                            { this@Cadence01StatusActivity.finish() }, 500L
                        )
                        return
                    }
                    this@Cadence01StatusActivity.toast("切换失败,请返回重试")
                    this@Cadence01StatusActivity.dismissLoadingDialog()
                }
            }
            switchModeTimer?.start()
        }
    }

    public override fun onStop() {
        super.onStop()
        dismissLoadingDialog()
        val countDownTimer = this.switchModeTimer
        countDownTimer?.cancel()
    }

    fun requestBattery() {
        val device = this.device
        if (device == null || device.address == null) {
            return
        }

        batteryView.postDelayed({
            val intent = Intent(BleCons.ACTION_REQUEST_BATTERY)
            intent.putExtra(BleCons.EXTRA_DEVICE_TYPE, SmartDevice.TYPE_CADENCE01)
            intent.putExtra(BleCons.EXTRA_DEVICE_ADDRESS, device.address)
            sendOrderedBroadcast(intent, null)
        }, 1600L)
    }

    fun requestDeviceInfo() {
        val device = this.device
        if (device == null || device.address == null) {
            return
        }
        val intent = Intent(BleCons.ACTION_REQUEST_DEVICE_INFORMATION)
        intent.putExtra(BleCons.EXTRA_DEVICE_TYPE, SmartDevice.TYPE_CADENCE01)
        intent.putExtra(BleCons.EXTRA_DEVICE_ADDRESS, device.address)
        sendOrderedBroadcast(intent, null)
    }

    private fun readDeviceInfo() {
        val device = this.device
        if (device == null || device.address == null) {
            return
        }

        batteryView.postDelayed({
            if (device.address == null) {
                return@postDelayed
            }
            val intent = Intent(BleCons.ACTION_READ_DEVICE_INFORMATION)
            intent.putExtra(BleCons.EXTRA_DEVICE_TYPE, SmartDevice.TYPE_CADENCE01)
            intent.putExtra(BleCons.EXTRA_DEVICE_ADDRESS, device.address)
            sendOrderedBroadcast(intent, null)
        }, 1800L)
    }

    @SuppressLint("SetTextI18n")
    fun setUIBattery(battery: Int) {
        val textView = this.batteryView
        textView.text = battery.toString() + Separators.PERCENT
    }

    fun setUIVersion(version: String?) {
        tvVersion.text = version
        if (version != null) {
            checkVersion(version)
        }
    }

    fun setUIManufacture(manufacture: String?) {
        tvManufacture.text = manufacture
    }

    fun setUIModel(model: String?) {
        tvModel.text = model
        title = model
    }

    override fun onDestroy() {
        unregisterReceiver(broadcastReceiver)
        DeviceHelper.unregisterConnectionStateListener(this)
        super.onDestroy()
    }

    private fun registerReceiver() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(BleCons.ACTION_BATTERY)
        intentFilter.addAction(BleCons.ACTION_DEVICE_INFORMATION)
        intentFilter.addAction(BleCons.ACTION_CADENCE_DATAS)
        intentFilter.addAction(BleCons.ACTION_PRESSURE_DATAS)
        intentFilter.addAction(BleCons.ACTION_READ_DEVICE_INFORMATION_RESULT)
        registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED);
    }

    private fun showWheelSettingDialog() {
        BiciAlertDialogBuilder(this).setItems(
            arrayOf(
                getString(R.string.mine_wheel_setting_dialog_item_custom),
                getString(R.string.mine_wheel_setting_dialog_item_check_table)
            )
        ) { _: DialogInterface?, i: Int ->
            val intent = Intent(
                this, WheelLengthSetting::class.java
            )
            intent.putExtra("auto", i != 0)
            startActivity(intent)
        }.show()
    }

    @SuppressLint("SetTextI18n")
    override fun onRefreshUI(displayPoint: DisplayPoint) {
        Log.d(TAG, "getSpeed=" + displayPoint.getSpeed(Utils.DOUBLE_EPSILON))
        Log.d(TAG, "getCadence=" + displayPoint.getCadence(0))
        val cadence = displayPoint.getCadence(0)
        val current = System.currentTimeMillis();
        if (cadence != 0 || (current - lastTime > 5000)) {//add delay for value = 0
            lastTime = current
            cadenceView.text = cadence.toString()
        }
        val speed = displayPoint.getSpeed(Utils.DOUBLE_EPSILON) * 3.6
        if (speed != 0.0 || (current - lastSpeedTime > 5000)) {
            lastSpeedTime = current
            speedView.text = decimalFormat.format(speed)
        }
    }

    override fun onConnectionStateChanged(smartDevice: SmartDevice, i: Int, i2: Int) {
        if (smartDevice.type == SmartDevice.TYPE_CADENCE01 && device != null && smartDevice.address == device!!.address) {
            if (i == DeviceManager.STATE_CONNECTED) {
                requestBattery()
            } else if (i == DeviceManager.STATE_DISCONNECTED) {
                if (mDfuProgressDialog?.isShowing == true) {
                    return
                }
                if (!isFinishing && !isSwitchMode && isShowFailToast) {
                    toast(R.string.mine_device_toast_connect_failed)
                    finish()
                }
            }
        }
    }

    private fun bindView() {
        speedView = binding.speedView
        cadenceView = binding.cadenceView
        batteryView = binding.batteryView
        wheelSettingView = binding.wheelSettingView
        wheelLengthView = binding.wheelLengthView
        unbindBtn = binding.unbindBtn
        llSpeed = binding.llSpeed
        llCadence = binding.llCadence
        radioSpeed = binding.radioSpeed
        radioCadence = binding.radioCadence
        radioGroupType = binding.radioGroup
        tvVersion = binding.versionName
        tvModel = binding.modelName
        tvManufacture = binding.manufactureName
        mIbUpgradeFirmware = binding.ibUpgradeFirmware
        mIbUpgradeFirmware.setOnClickListener { upgradeFirmware() }
//        mIbUpgradeFirmware.setVisibility(if (DeviceContext.getDeviceConfiguration().isDfuDebuggable) View.VISIBLE else View.GONE)
    }


    private fun upgradeFirmware() {
        AlertDialog.Builder(this).setMessage(
            getString(
                R.string.message_upgrade_fw_confirm, device!!.name
            )
        ).setPositiveButton(
            R.string.str_sync_confirm
        ) { _: DialogInterface?, _: Int ->

            onDfuProcessMessage(getString(R.string.message_upgrade_fw_starting))
            lifecycleScope.launch(Dispatchers.IO) {
                try {
                    getExternalFilesDir(null)?.let {
                        val path = it.absolutePath + "/" + Environment.DIRECTORY_DOWNLOADS
                        val file = File(path)
                        if (!file.exists()){
                            file.mkdirs();
                        }
                        dfuFilePath = path + "/" + "v" + System.currentTimeMillis() + ".zip"
                    }
                    FileDownloadUtils.downloadFile(downloadUrl,
                        dfuFilePath,
                        object : FileDownloadUtils.DownloadProgressListener {
                            override fun onProgress(progress: Int) {

                            }

                            override fun onComplete() {
                                runOnUiThread {
                                    if (!isFinishing) {
                                        startUpgrade()
                                    }
                                }

                            }

                            override fun onError(errorMessage: String?) {
                                runOnUiThread {
                                    if (!isFinishing) {
                                        dismissProgressDialog()
                                        toast(R.string.toast_download_failed)
                                    }
                                }
                            }
                        })
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }.setNegativeButton(R.string.cancel, null as DialogInterface.OnClickListener?).show()
    }

    private fun startUpgrade() {
        if (this.mDfuContext == null) {
            val device = this.device
            mDfuContext = DfuContext(
                this, device!!.address, device.name, device.type, dfuFilePath, true, this
            )
//            mDfuContext!!.isUseUri(true) //select ./ local file
        }
        mDfuContext!!.enterDfuMode()
    }


    public override fun onActivityResult(i: Int, i2: Int, intent: Intent?) {
        super.onActivityResult(i, i2, intent)
        val dfuContext = this.mDfuContext
        if (dfuContext != null) {
            try {
                dfuContext.parseDfuFile(i, i2, intent)
            } catch (e: Throwable) {
                throw RuntimeException(e)
            }
        }
    }


    private fun showProgressDialog(charSequence: CharSequence?) {
        val progressDialog = this.mDfuProgressDialog
        if (progressDialog == null) {
            val show = ProgressDialog(this, android.R.style.Theme_Material_Dialog)
            this.mDfuProgressDialog = show
            show.setCanceledOnTouchOutside(false)
            mDfuProgressDialog!!.setCancelable(false)
            return
        }
        progressDialog.setMessage(charSequence)
        mDfuProgressDialog!!.show()
    }

    private fun dismissProgressDialog() {
        val progressDialog = this.mDfuProgressDialog
        progressDialog?.dismiss()
    }

    override fun onDfuProcessMessage(str: String) {
        showProgressDialog(str)
    }

    override fun onProgressChanged(i: Int) {
        showProgressDialog(getString(R.string.message_upgrade_fw_in_progress, i))
    }

    override fun onUpgradeCompleted() {
        mDfuContext!!.setIncremental(false)
        dismissProgressDialog()
        XZDeviceHelper.setDeviceFwVersion(device?.address, "")
        DeviceContext.saveDeviceVersion(device!!.address, verName)
        AlertDialog.Builder(this).setMessage(R.string.message_upgrade_fw_on_success)
            .setPositiveButton(
                R.string.str_sync_confirm
            ) { _: DialogInterface?, i: Int -> finish() }.setCancelable(false).show()
            .setCanceledOnTouchOutside(false)
    }

    override fun onUpgradeFail(str: String) {
        dismissProgressDialog()
        AlertDialog.Builder(this).setMessage(R.string.message_upgrade_fw_fail).setPositiveButton(
            R.string.str_sync_confirm
        ) { _: DialogInterface?, i: Int ->
            try {
                startUpgrade()
            } catch (e: Throwable) {
                throw RuntimeException(e)
            }
        }.setNegativeButton(
            R.string.cancel
        ) { _: DialogInterface?, i: Int ->
            AlertDialog.Builder(this@Cadence01StatusActivity)
                .setMessage(R.string.message_upgrade_fw_exit).setPositiveButton(
                    R.string.str_sync_confirm, null as DialogInterface.OnClickListener?
                ).setOnDismissListener { finish() }.show()
        }.setCancelable(false).show().setCanceledOnTouchOutside(false)
    }

    override fun onError(i: Int, i2: Int, str: String) {
        if (!isFinishing) {
            dismissProgressDialog()
            AlertDialog.Builder(this).setMessage(R.string.message_upgrade_fw_fail)
                .setPositiveButton(
                    R.string.str_sync_confirm
                ) { _: DialogInterface?, i: Int ->
                    try {
                        mDfuContext!!.setIncremental(true)
                        startUpgrade()
                    } catch (e: Throwable) {
                        throw RuntimeException(e)
                    }
                }.setCancelable(false).show().setCanceledOnTouchOutside(false)
        }
    }

    override fun onUpgradeStarted() {
    }

    companion object {
        private const val TAG = "Cadence01StatusActivity"
    }


    private fun checkVersion(versionNumber: String?) {
        if (!isChecking && versionNumber != null /*&& version.contains("v")*/) {
            try {
                isChecking = true
//                var versionNumber = version.substring(version.indexOfLast { 'v' == it } + 1)
                MyHttpClient.getHeartRateVersion(object : BiCiCallback() {
                    override fun onResponseString(str: String) {
                        try {
                            isChecking = false
                            val jo = JSONObject(str)
                            val dataObject = jo.optJSONObject("data")
                            if (!isFinishing && dataObject != null) {
                                verName = /*"v" + */dataObject.optString("verName")
                                downloadUrl = dataObject.optString("downloadUrl")
                                if (!downloadUrl.isNullOrEmpty()) {
                                    runOnUiThread { binding.ibUpgradeFirmware.setVisibility(View.VISIBLE) }
                                }
                            }
                        } catch (e: java.lang.Exception) {
                            e.printStackTrace()
                        }
                    }

                    override fun onResponseFail(str: String?) {
                        super.onResponseFail(str)
                        isChecking = false
                    }
                }, "cad01", versionNumber)
            } catch (e: Exception) {
                e.printStackTrace()
                isChecking = false
            }
        }
    }
}